<template>
    <div v-if="hasError" class="error-boundary">
        <div class="error-content">
            <div class="error-icon">
                <i class="pi pi-exclamation-triangle"></i>
            </div>
            <h3>{{ errorTitle }}</h3>
            <p>{{ errorMessage }}</p>
            <div class="error-actions">
                <Button label="重新加载" @click="retry" :loading="retrying" severity="secondary" class="mr-2" />
                <Button label="返回首页" @click="goHome" severity="primary" />
            </div>
            <details v-if="showDetails" class="error-details">
                <summary>技术详情</summary>
                <pre>{{ errorDetails }}</pre>
            </details>
        </div>
    </div>
    <slot v-else></slot>
</template>

<script setup>
import { useErrorHandler } from '@/utils/errorHandler';
import Button from 'primevue/button';
import { computed, onBeforeUnmount, onErrorCaptured, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';

const props = defineProps({
    fallback: {
        type: Function,
        default: null
    },
    onError: {
        type: Function,
        default: null
    },
    level: {
        type: String,
        default: 'component', // 'component' | 'page' | 'app'
        validator: (value) => ['component', 'page', 'app'].includes(value)
    },
    showDetails: {
        type: Boolean,
        default: false
    }
});

const router = useRouter();
const errorHandler = useErrorHandler();

const hasError = ref(false);
const errorInfo = ref(null);
const retrying = ref(false);

// 根据错误级别确定显示内容
const errorTitle = computed(() => {
    switch (props.level) {
        case 'app':
            return '应用程序遇到了问题';
        case 'page':
            return '页面加载失败';
        default:
            return '组件出现错误';
    }
});

const errorMessage = computed(() => {
    if (errorInfo.value?.message) {
        return errorInfo.value.message;
    }

    switch (props.level) {
        case 'app':
            return '应用程序遇到了意外错误，请尝试刷新页面或联系技术支持。';
        case 'page':
            return '页面无法正常显示，请检查网络连接或稍后重试。';
        default:
            return '该功能暂时无法使用，请稍后重试。';
    }
});

const errorDetails = computed(() => {
    if (!errorInfo.value) return '';

    return JSON.stringify({
        message: errorInfo.value.message,
        stack: errorInfo.value.stack,
        componentStack: errorInfo.value.componentStack,
        timestamp: new Date().toISOString()
    }, null, 2);
});

// 捕获子组件错误
onErrorCaptured((error, instance, info) => {
    console.error('ErrorBoundary caught an error:', error, info);

    hasError.value = true;
    errorInfo.value = {
        message: error.message,
        stack: error.stack,
        componentStack: info,
        instance: instance
    };

    // 调用自定义错误处理
    if (props.onError) {
        props.onError(error, instance, info);
    }

    // 记录错误
    errorHandler.logError('Component Error', {
        message: error.message,
        stack: error.stack,
        componentStack: info,
        level: props.level
    });

    // 阻止错误向上传播
    return false;
});

// 全局错误处理
onMounted(() => {
    if (props.level === 'app') {
        // 捕获未处理的Promise拒绝
        window.addEventListener('unhandledrejection', handleUnhandledRejection);

        // 捕获全局JavaScript错误
        window.addEventListener('error', handleGlobalError);
    }
});

const handleUnhandledRejection = (event) => {
    console.error('Unhandled promise rejection:', event.reason);

    hasError.value = true;
    errorInfo.value = {
        message: event.reason?.message || 'Promise rejection',
        stack: event.reason?.stack,
        type: 'unhandledrejection'
    };

    errorHandler.logError('Unhandled Rejection', {
        reason: event.reason,
        promise: event.promise
    });

    event.preventDefault();
};

const handleGlobalError = (event) => {
    console.error('Global error:', event.error);

    hasError.value = true;
    errorInfo.value = {
        message: event.message,
        stack: event.error?.stack,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        type: 'javascript'
    };

    errorHandler.logError('Global Error', {
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno
    });
};

// 重试功能
const retry = async () => {
    retrying.value = true;

    try {
        // 等待一小段时间
        await new Promise(resolve => setTimeout(resolve, 500));

        // 重置错误状态
        hasError.value = false;
        errorInfo.value = null;

        // 如果有自定义fallback，调用它
        if (props.fallback) {
            await props.fallback();
        }
    } catch (error) {
        console.error('Retry failed:', error);
        errorHandler.handleNetworkError(error, '重试失败');
    } finally {
        retrying.value = false;
    }
};

// 返回首页
const goHome = () => {
    router.push('/');
};

// 清理事件监听器
onBeforeUnmount(() => {
    if (props.level === 'app') {
        window.removeEventListener('unhandledrejection', handleUnhandledRejection);
        window.removeEventListener('error', handleGlobalError);
    }
});
</script>

<style scoped>
.error-boundary {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    padding: 2rem;
    background-color: var(--surface-ground);
    border-radius: var(--border-radius);
    border: 1px solid var(--surface-border);
}

.error-content {
    text-align: center;
    max-width: 500px;
}

.error-icon {
    margin-bottom: 1rem;
}

.error-icon i {
    font-size: 3rem;
    color: var(--orange-500);
}

.error-content h3 {
    margin-bottom: 1rem;
    color: var(--text-color);
    font-size: 1.5rem;
}

.error-content p {
    margin-bottom: 2rem;
    color: var(--text-color-secondary);
    line-height: 1.6;
}

.error-actions {
    margin-bottom: 2rem;
}

.error-details {
    text-align: left;
    margin-top: 2rem;
    border: 1px solid var(--surface-border);
    border-radius: var(--border-radius);
    background-color: var(--surface-card);
}

.error-details summary {
    padding: 1rem;
    cursor: pointer;
    background-color: var(--surface-hover);
    border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.error-details pre {
    padding: 1rem;
    margin: 0;
    background-color: var(--surface-ground);
    color: var(--text-color);
    font-size: 0.875rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
}
</style>
